 #ifndef _GCHRONO_H_
#define _GCHRONO_H_

#include <unistd.h> 
#include <ctime>

#ifdef GMPI
#include <mpi.h>
#endif


inline double gtime() {
#ifdef GMPI
  return MPI_Wtime() ;
#else
  return (double)clock() / (double)CLOCKS_PER_SEC ;
#endif

}


/**
 * A chrono to measure the time elapse in seconds
 */
class gchrono {
 private:
  /* clock_t cpuStart, cpuStop ; */
  /* clock_t totalTime ; */
  double cpuStart, cpuStop ;
  double totalTime ;

 public:
    gchrono(){totalTime = 0 ;}

    inline void reset() {totalTime = 0 ;}

    inline virtual void start() { cpuStart = gtime() ; }
    inline virtual void stop() { cpuStop = gtime() ; totalTime += cpuStop - cpuStart ; }
    inline double getRunningTime() { return gtime() - cpuStart ; }
    inline double getTotalTime() { return totalTime ; }
    inline double getTotalTimeSec() { return totalTime ; }
    inline double getTotalTimeMs() { return (double)1000.0*totalTime ; }
    inline double getStopTimeMs() { return (double)1000.0*cpuStop ; }
} ;




/**
 * A chrono to measure the time elapse in milliseconds
 */
class gchronoms {
 private:
  clock_t cpuStart, cpuStop ; 
  clock_t totalClock ; 

 public:
    gchronoms(){totalClock = 0 ;}

    inline void reset() {totalClock = 0 ;}

    inline void start() { cpuStart = clock() ; }
    inline void stop() { cpuStop = clock() ; totalClock += cpuStop - cpuStart ; }
    inline long getTotalTimeMs() { return (long)(1000.0*(double)totalClock / (double)CLOCKS_PER_SEC) ; }
    inline long getStopTimeMs() { return (long)(1000.0*(double)cpuStop / (double)CLOCKS_PER_SEC) ; }
} ;




/**
 * A alarm in seconds
 */
class galarmsec {
 protected:
  // for alarm
  double delay ;
  double alarm ;


 public:
    galarmsec(){}

    inline void setAlarmDuration(double s) { delay = s ; rearm() ;}
    inline double getAlarmDuration() {return delay ;}
    inline void rearm() {alarm = gtime() + delay ;}

    /**
     * @return 1 if the alarm triggers, 0 otherwise
     */ 
    inline int testAndRearmAlarm() {
      if (gtime()>alarm) { rearm() ; return 1 ;}
      return 0 ;
    }
} ;

class galarmms {
 protected:
  // for alarm
  long delayms ;
  clock_t clockdelay ;
  clock_t clockalarm ;


 public:
    galarmms(){}

    inline void setAlarmDurationMs(long s) { delayms = s ; clockdelay = clock()+(s*CLOCKS_PER_SEC)/1000 ; rearm() ;}
    inline clock_t getAlarmDuration() {return delayms ;}
    inline void rearm() {clockalarm = clock() + clockdelay ;}

    /**
     * @return 1 if the alarm triggers, 0 otherwise
     */ 
    inline int testAndRearmAlarm() {
      if (clock()>clockalarm) { rearm() ; return 1 ;}
      return 0 ;
    }
} ;

#endif
